﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using TestOnlineProject.Models.Entities;
using TestOnlineProject.Common;
using TestOnlineProject.Models.DataAccess;

namespace TestOnlineProject.Models.BusinessLogic
{
    public class SectionBLO
    {
        SectionDAO sectionDAO = new SectionDAO();
        SectionQuestionDAO sectionQuestionDAO = new SectionQuestionDAO();
        ParticipantDAO participantDAO = new ParticipantDAO();

        /// <summary>
        /// Select category list.
        /// </summary>
        /// <param name="page">Number of page</param>
        /// <param name="subjectId">Subject identity key</param>
        /// <param name="keyWord">Search key word</param>
        /// <param name="column">Column name</param>
        /// <param name="sort">Sort type</param>
        /// <returns>Category list</returns>

        public List<Section> ToList(ref List<NoModel> noList, int? page, string keyWord = "", string createdBy = "", int actualUser = 0, int subjectId = 0, string column = "", string sort = "")
        {
            try
            {
                // Search section by subjectid.
                var sections = sectionDAO.SelectBySubjectId(subjectId).OrderBy(s => s.SectionId).ToList();

                if (!HttpContext.Current.User.IsInRole("1"))
                {
                    sections = sections.Where(s => s.IsActivated == true).ToList();
                }

                // Search section by keywords.
                sections = sections.Where(s => s.Name.ToLower().Contains(keyWord.ToLower())).ToList();

                // Search by 'Created By'.
                if (createdBy == "")
                {
                    sections = sections.ToList();
                }
                if (createdBy == "mine")
                {
                    sections = sections.Where(q => q.UserId == int.Parse(HttpContext.Current.User.Identity.Name)).ToList();
                }
                if (createdBy == "admin")
                {
                    sections = sections.Where(q => (q.User.Role.Name == "Admin")).ToList();
                }
                if (createdBy == "teachers")
                {
                    sections = sections.Where(q => (q.User.Role.Name == "Teacher")).ToList();
                }
                if (createdBy == "students")
                {
                    sections = sections.Where(q => (q.User.Role.Name == "Student")).ToList();
                }
                if (createdBy == "actualUser")
                {
                    sections = sections.Where(q => ((q.User.UserId == actualUser))).ToList();
                }

                // Sort by column.
                switch (column + sort)
                {
                    case "NoAsc":
                        sections = sections.Where(c => c.SubjectId == subjectId).OrderBy(c => c.SectionId).ToList();
                        break;
                    case "NoDesc":
                        sections = sections.Where(c => c.SubjectId == subjectId).OrderByDescending(c => c.SectionId).ToList();
                        break;
                    case "NameAsc":
                        sections = sections.Where(c => c.SubjectId == subjectId).OrderBy(c => c.Name).ToList();
                        break;
                    case "NameDesc":
                        sections = sections.Where(c => c.SubjectId == subjectId).OrderByDescending(c => c.Name).ToList();
                        break;
                    case "IsActivatedAsc":
                        sections = sections.Where(c => c.SubjectId == subjectId).OrderBy(c => c.IsActivated).ToList();
                        break;
                    case "IsActivatedDesc":
                        sections = sections.Where(p => p.SubjectId == subjectId).OrderByDescending(c => c.IsActivated).ToList();
                        break;
                    default: break;
                }

                // Generate no. List.
                foreach (var s in sections)
                {
                    noList.Add(new NoModel() { Id = s.SectionId });
                }
                noList = noList.OrderBy(s => s.Id).ToList();
                for (int i = 0; i < noList.Count; i++)
                {
                    noList[i].No = i + 1;
                }

                return sections;
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="subjectId"></param>
        /// <returns></returns>

        public List<Section> ToList(int subjectId, int userId)
        {
            try
            {
                var sections = sectionDAO.SelectBySubjectIdUserId(subjectId, userId).Where(s => s.IsActivated).ToList();
                return sections;
            }
            catch (Exception)
            {
                throw;
            }
        }
        public List<Section> ToList(int subjectId = 0)
        {
            try
            {
                List<Section> sections = sectionDAO.SelectBySubjectId(subjectId).Where(s => s.IsActivated).ToList();
                return sections.Where(s => s.UserId == int.Parse(HttpContext.Current.User.Identity.Name)).ToList();
            }
            catch (Exception)
            {
                throw;
            }
        }
        public List<Section> ToList(string term, int subjectId = 0)
        {
            try
            {
                List<Section> sections = sectionDAO.SelectBySubjectId(subjectId).Where(s => s.IsActivated).ToList();

                if (term.IndexOf("/") == 0 && term.Length == 1)
                {
                    return sections;
                }

                else if (term.IndexOf("/m") == 0)
                {
                    return sections.Where(s => s.UserId == int.Parse(HttpContext.Current.User.Identity.Name)).ToList();
                }

                else if (term.IndexOf("/a") == 0)
                {
                    return sections.Where(s => s.User.RoleId == 1 && s.IsActivated).ToList();
                }

                else if (term.IndexOf("/t") == 0)
                {
                    return sections.Where(s => s.User.RoleId == 2 && s.IsActivated).ToList();
                }

                else if (term.IndexOf("/s") == 0)
                {
                    return sections.Where(s => s.User.RoleId == 3 && s.IsActivated).ToList();
                }

                else if (term.IndexOf("@") == 0)
                {
                    var name = term.Substring(1).ToLower();
                    return sections.Where(s => s.User.FullName.ToLower().Contains(name) || s.User.Username.ToLower().Contains(name) && s.IsActivated).ToList();
                }

                else
                {
                    return sections.Where(s => s.Name.ToLower().Contains(term.ToLower())).ToList();
                }

            }
            catch (Exception)
            {
                throw;
            }
        }

        public List<Section> ToList()
        {
            try
            {
                var sections = sectionDAO.Select();
                return sections;
            }
            catch (Exception)
            {
                throw;
            }
        }

        public List<Section> Recommend()
        {
            try
            {
                var list = sectionDAO.Select().Where(s => s.IsActivated).OrderByDescending(s => s.SectionId).ToList();
                if (!HttpContext.Current.User.IsInRole("1"))
                {
                    list = list.Where(s => s.Subject.Participants.Where(p => p.IsActivated && p.UserId == int.Parse(HttpContext.Current.User.Identity.Name)).ToList().Count > 0 && s.Subject.IsActivated).ToList();
                }
                return list;
            }
            catch (Exception)
            {
                throw;
            }
        }

        public bool CheckAccessible(int userId, int subjectId, int sectionId = 0, bool modify = false)
        {
            try
            {
                // Admin can access.
                if (HttpContext.Current.User.IsInRole("1"))
                {
                    return true;
                }

                var section = sectionDAO.SelectBySectionId(sectionId);

                // Whhen search sections.
                if (section == null)
                {
                    var participant = participantDAO.SelectByUserIdSubjectId(userId, subjectId);
                    if (participant != null)
                    {
                        if (participant.IsActivated && participant.Subject.IsActivated && participant.User.IsActivated)
                        {
                            return true;
                        }
                    }
                }

                    // When details, edit
                else
                {
                    var participant = participantDAO.SelectByUserIdSubjectId(userId, subjectId);
                    if (participant != null)
                    {
                        if (participant.IsActivated && participant.Subject.IsActivated && participant.User.IsActivated)
                        {
                            // Owner access.
                            if (section.UserId == userId)
                            {
                                return true;
                            }

                                // Others access.
                            else
                            {
                                if (!modify && section.IsActivated)
                                {
                                    return true;
                                }
                            }
                        }

                    }
                }

                return false;
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// Add new category.
        /// </summary>
        /// <param name="section">Category object</param>
        /// <returns>Number of category has been added</returns>

        public int Add(Section section)
        {
            try
            {
                // Add section.
                section.CreatedTime = DateTime.Now;
                section.LastEditedTime = DateTime.Now;
                section.IsActivated = true;
                int result = sectionDAO.Insert(section);

                return result;
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// Find categoty by id.
        /// </summary>
        /// <param name="sectionId">Category ID</param>
        /// <returns>Category object</returns>

        public Section Find(int sectionId = 0)
        {
            try
            {
                // Select category by id.
                var section = sectionDAO.SelectBySectionId(sectionId);

                return section;
            }
            catch (Exception)
            {
                throw;
            }
        }

        public int Modify(Section section)
        {
            try
            {
                int result = 0;

                // Select a section by id.
                var sec = sectionDAO.SelectBySectionId(section.SectionId);

                if (!sec.LastEditedTime.ToString().Equals(section.LastEditedTime.ToString()))
                {
                    return -1;
                }

                // Modified section.
                sec.Name = section.Name;
                sec.LastEditedTime = DateTime.Now;
                result = sectionDAO.Update(section);

                return result;
            }
            catch (Exception)
            {
                throw;
            }
        }


        /// <summary>
        /// Remove categories.
        /// </summary>
        /// <param name="id">Category ids string</param>
        /// <returns>Number of category has been removed</returns>

        public int Remove(string ids = "")
        {
            try
            {
                StringHelper spliter = new StringHelper();

                // Split id string to int array.
                int[] idInt = spliter.Split(ids);

                int result = 0;

                // Delete sections.
                foreach (var i in idInt)
                {
                    var section = sectionDAO.SelectBySectionId(i);

                    // Admin or owner can access.
                    if (HttpContext.Current.User.IsInRole("1") || int.Parse(HttpContext.Current.User.Identity.Name) == section.UserId)
                    {
                        result += sectionDAO.Delete(i);
                    }
                }

                return result;
            }
            catch (Exception)
            {
                throw;
            }
        }

        public int Deactivate(string ids = "")
        {
            try
            {
                StringHelper spliter = new StringHelper();

                // Split id string to int array.
                int[] idInt = spliter.Split(ids);

                int result = 0;

                // Deactivate questions.
                foreach (var i in idInt)
                {
                    // Select question by id.
                    var section = sectionDAO.SelectBySectionId(i);

                    if (HttpContext.Current.User.IsInRole("1"))
                    {
                        // Check question is activated?
                        if (section.IsActivated)
                        {
                            section.IsActivated = false;
                            result += sectionDAO.Update(section);

                        }
                    }
                }

                return result;
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// Activate questions
        /// </summary>
        /// <param name="ids">Question ids string</param>
        /// <returns>Number of question has been activated</returns>

        public int Activate(string ids = "")
        {
            try
            {
                StringHelper spliter = new StringHelper();

                // Split id string to int array.
                int[] idInt = spliter.Split(ids);

                int result = 0;

                // Deactivate questions.
                foreach (var i in idInt)
                {
                    // Select question by id.
                    var section = sectionDAO.SelectBySectionId(i);

                    if (HttpContext.Current.User.IsInRole("1"))
                    {
                        // check question is deactivated?
                        if (!section.IsActivated)
                        {
                            section.IsActivated = true;
                            result += sectionDAO.Update(section);
                        }
                    }
                }

                return result;
            }
            catch (Exception)
            {
                throw;
            }
        }

        public int AddQuestions(int sectionId, string ids = "")
        {
            try
            {
                if (sectionDAO.SelectBySectionId(sectionId).UserId != int.Parse(HttpContext.Current.User.Identity.Name))
                {
                    return 0;
                }

                StringHelper splitter = new StringHelper();

                // Split id string to int array.
                int[] questionIdArr = splitter.Split(ids);

                int result = 0;

                // Deactivate sections by id.
                foreach (var i in questionIdArr)
                {
                    var sectionQuestion = sectionQuestionDAO.SelectBySectionIdQuestionId(sectionId, i);

                    if (sectionQuestion == null)
                    {
                        var sq = new SectionQuestion()
                        {
                            SectionId = sectionId,
                            QuestionId = i
                        };

                        result += sectionQuestionDAO.Insert(sq);
                    }
                }

                return result;
            }
            catch (Exception)
            {
                throw;
            }
        }

        public int RemoveQuestions(int sectionId, string ids = "")
        {
            try
            {
                if (sectionDAO.SelectBySectionId(sectionId).UserId != int.Parse(HttpContext.Current.User.Identity.Name))
                {
                    return 0;
                }

                StringHelper splitter = new StringHelper();

                // Split id string to int array.
                int[] questionIdArr = splitter.Split(ids);

                int result = 0;

                // Deactivate sections by id.
                foreach (var i in questionIdArr)
                {
                    var sectionQuestion = sectionQuestionDAO.SelectBySectionIdQuestionId(sectionId, i);

                    if (sectionQuestion != null)
                    {
                        result += sectionQuestionDAO.Delete(sectionQuestion.SectionId, sectionQuestion.QuestionId);
                    }
                }

                return result;
            }
            catch (Exception)
            {
                throw;
            }
        }
    }
}